package net.zoneland.knowledge.utils;

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.Arrays;
import java.util.List;

public class ExcelFillCellMergeStrategyUtils implements CellWriteHandler {
    /**
     * 需要合并列的下标，从0开始
     */
    private final int[] mergeColumnIndex;
    /**
     * 从第几行开始合并，表头下标为0
     */
    private final int mergeRowIndex;

    public ExcelFillCellMergeStrategyUtils(final int mergeRowIndex, final int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(final WriteSheetHolder writeSheetHolder,
                                 final WriteTableHolder writeTableHolder,
                                 final Row row,
                                 final Head head,
                                 final Integer integer,
                                 final Integer integer1,
                                 final Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(final WriteSheetHolder writeSheetHolder,
                                final WriteTableHolder writeTableHolder,
                                final Cell cell,
                                final Head head,
                                final Integer integer,
                                final Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(final WriteSheetHolder writeSheetHolder,
                                 final WriteTableHolder writeTableHolder,
                                 final List<WriteCellData<?>> list,
                                 final Cell cell,
                                 final Head head,
                                 final Integer integer,
                                 final Boolean aBoolean) {

        //当前行
        final int curRowIndex = cell.getRowIndex();
        //当前列
        final int curColIndex = cell.getColumnIndex();

        final boolean isMergeWithPrevRow = curRowIndex > mergeRowIndex && Arrays.stream(mergeColumnIndex)
                .anyMatch(columnIndex -> curColIndex == columnIndex);
        if (isMergeWithPrevRow) {
            mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
        }

    }

    /**
     * 合并单元格
     * @param writeSheetHolder writeSheetHolder
     * @param cell cell
     * @param curRowIndex curRowIndex
     * @param curColIndex curColIndex
     */
    private void mergeWithPrevRow(final WriteSheetHolder writeSheetHolder,
                                  final Cell cell,
                                  final int curRowIndex,
                                  final int curColIndex) {
        //获取当前行的当前列的数据和上一行的当前列列数据，通过上一行数据是否相同进行合并
        final Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() :
                cell.getNumericCellValue();
        // 当获取不到上一行数据时，使用缓存sheet中数据
        final Row preRow = cell.getSheet().getRow(curRowIndex - 1) == null
                ? writeSheetHolder.getCachedSheet().getRow(curRowIndex - 1)
                : cell.getSheet().getRow(curRowIndex - 1);
        final Cell preCell = preRow.getCell(curColIndex);
        final Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue()
                : preCell.getNumericCellValue();

        // 当获取不到上一行数据时，使用缓存sheet中数据
        final Row curRow = cell.getSheet().getRow(curRowIndex) == null
                ? writeSheetHolder.getCachedSheet().getRow(curRowIndex)
                : cell.getSheet().getRow(curRowIndex);

        final Cell curFirstCell = curRow.getCell(0);
        final Object curFirstData = curFirstCell.getCellTypeEnum() == CellType.STRING ? curFirstCell.getStringCellValue()
                : curFirstCell.getNumericCellValue();

        final Cell preFirstCell = preRow.getCell(0);
        final Object preFirstData = preFirstCell.getCellTypeEnum() == CellType.STRING ? preFirstCell.getStringCellValue()
                : preFirstCell.getNumericCellValue();

        // 比较当前行的第一列的单元格与上一行是否相同，相同合并当前单元格与上一行
        if (curData.equals(preData) && curFirstData.equals(preFirstData)) {
            final Sheet sheet = writeSheetHolder.getSheet();
            final List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();

            final boolean isMerged = mergeRegions.stream()
                    .filter(cellRangeAddr -> cellRangeAddr.isInRange(curRowIndex - 1, curColIndex))
                    // 根据业务需求需要取第一个被合并的单元格做操作
                    .findFirst()
                    .map(cellRangeAddr -> {
                        // 若上一个单元格已经被合并，则先移出原有的合并单元，再重新添加合并单元
                        sheet.removeMergedRegion(mergeRegions.indexOf(cellRangeAddr));
                        cellRangeAddr.setLastRow(curRowIndex);
                        sheet.addMergedRegion(cellRangeAddr);
                        return true;
                    })
                    .orElse(false);

            // 若上一个单元格未被合并，则新增合并单元
            if (!isMerged) {
                final CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
                        curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
}
